package com.vshop.platform.system.crud.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;

import com.vshop.framework.core.constant.Const;
import com.vshop.framework.core.exception.ServiceException;
import com.vshop.framework.core.util.MapstructUtil;
import com.vshop.framework.mybatisflex.page.PageData;
import com.vshop.framework.mybatisflex.page.PageQuery;
import com.vshop.platform.system.crud.dao.SysRoleDao;
import com.vshop.platform.system.crud.dao.SysRoleDeptDao;
import com.vshop.platform.system.crud.dao.SysRoleMenuDao;
import com.vshop.platform.system.crud.dao.SysUserRoleDao;
import com.vshop.platform.system.domain.entity.SysRole;
import com.vshop.platform.system.domain.entity.SysUserRole;
import com.vshop.platform.system.domain.param.SysRoleParam;
import com.vshop.platform.system.domain.param.SysUserParam;
import com.vshop.platform.system.domain.vo.SysRoleVo;
import com.vshop.platform.system.domain.vo.SysUserVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.vshop.platform.system.domain.entity.table.SysUserRoleTableDef.SysUserRoleTable;


@Slf4j
@RequiredArgsConstructor
@Service
public class SysRoleService {
    private final DataScopeService dataScopeService;
    private final SysRoleDao sysRoleDao;
    private final SysRoleMenuDao sysRoleMenuDao;
    private final SysRoleDeptDao sysRoleDeptDao;
    private final SysUserRoleDao sysUserRoleDao;

    public PageData<SysRoleVo> page(SysRoleParam param, PageQuery pageQuery) {
        QueryWrapper queryWrapper = sysRoleDao.buildQueryWrapper(param);
        Page<SysRoleVo> page = sysRoleDao.pageAs(pageQuery.build(), queryWrapper, SysRoleVo.class);
        return PageData.build(page);
    }

    @Transactional
    public boolean save(SysRoleParam param) {

        sysRoleDao.checkRoleAllowed(param);
        if (sysRoleDao.checkExistRoleName(param)) {
            throw new ServiceException("新增角色'" + param.getRoleName() + "'失败，角色名称已存在");
        }
        if (sysRoleDao.checkExistRoleKey(param)) {
            throw new ServiceException("新增角色'" + param.getRoleKey() + "'失败，角色权限已存在");
        }
        SysRole entity = MapstructUtil.convert(param, SysRole.class);
        Assert.notNull(entity, "添加对象不能为空");
        entity.setDataScope("1");//默认1：全部数据权限
        return sysRoleDao.save(entity);
    }

    @Transactional
    public boolean update(SysRoleParam param) {

        sysRoleDao.checkRoleAllowed(param);
        dataScopeService.checkRoleDataScope(param.getRoleId());

        if (sysRoleDao.checkExistRoleName(param)) {
            throw new ServiceException("修改角色'" + param.getRoleName() + "'失败，角色名称已存在");
        }
        if (sysRoleDao.checkExistRoleKey(param)) {
            throw new ServiceException("修改角色'" + param.getRoleKey() + "'失败，角色权限已存在");
        }
        if (ObjectUtil.equals(param.getStatus(), Const.StatusDisable)
                && sysRoleDao.checkRoleHasUserByRoleId(param.getRoleId())) {
            throw new ServiceException("角色已分配，不能停用!");
        }
//        if (updated) {
//            roleService.cleanOnlineUserByRole(roleBo.getRoleId());
//            return R.ok();
//        }
        SysRole entity = MapstructUtil.convert(param, SysRole.class);
        Assert.notNull(entity, "修改对象不能为空");

        return sysRoleDao.updateById(entity);
    }


    public boolean removeByIds(List<Long> ids) {
        ids.forEach(id -> {
            SysRoleParam roleBo = new SysRoleParam();
            roleBo.setRoleId(id);
            sysRoleDao.checkRoleAllowed(roleBo);
            dataScopeService.checkRoleDataScope(id);
            SysRole entity = sysRoleDao.getById(id);
            if (ObjectUtil.equals(entity.getStatus(), Const.StatusNormal)
                    && sysRoleDao.checkRoleHasUserByRoleId(entity.getRoleId())) {
                throw new ServiceException(String.format("%1$s 角色已分配,不能删除!", entity.getRoleName()));
            }
        });
        // 删除角色与菜单关联
        sysRoleMenuDao.removeRoleMenuByRoleIds(ids);
        // 删除角色与部门关联
        sysRoleDeptDao.removeRoleDeptByRoleIds(ids);

        //逻辑删除：update sys_role set del_flag = '1' where role_id in
        return sysRoleDao.removeByIds(ids);
    }


    /**
     * 查询当前角色已分配的用户列表 / 可条件搜索
     *
     * @param param 用户信息
     * @return 用户信息集合信息
     */
    public PageData<SysUserVo> pageAllocatedUser(SysUserParam param, PageQuery pageQuery) {
        QueryWrapper queryWrapper = sysUserRoleDao.pageAllocatedUserQueryWrapper(param);
        Page<SysUserVo> page = sysUserRoleDao.pageAs(pageQuery.build(), queryWrapper, SysUserVo.class);
        return PageData.build(page);
    }

    /**
     * 查询当前角色未分配的用户列表 (用户列表包括其他角色已分配的用户) / 可条件搜索
     *
     * @param param 用户信息
     * @return 用户信息集合信息
     */
    public PageData<SysUserVo> pageUnAllocatedUser(SysUserParam param, PageQuery pageQuery) {

        QueryWrapper queryWrapper = sysUserRoleDao.pageUnAllocatedUserQueryWrapper(param);
        Page<SysUserVo> page = sysUserRoleDao.pageAs(pageQuery.build(), queryWrapper, SysUserVo.class);
        return PageData.build(page);
    }


    /**
     * 取消授权用户:删除用户和角色关联信息
     * delete from sys_user_role where user_id=#{userId} and role_id=#{roleId}
     *
     * @param roleId 角色ID
     * @param userId 需要删除的用户数据 ID
     * @return 结果:true 删除成功，false 删除失败
     */
    public boolean cancelAuthUser(Long roleId, Long userId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .from(SysUserRoleTable)
                .where(SysUserRoleTable.UserId.eq(userId))
                .and(SysUserRoleTable.RoleId.eq(roleId));
        return sysUserRoleDao.remove(queryWrapper);
    }

    /**
     * 批量取消授权用户:删除用户和角色关联信息
     * delete from sys_user_role where role_id=#{roleId} and user_id in
     *
     * @param roleId  角色ID
     * @param userIds 需要删除的用户数据ID
     * @return 结果:true 删除成功，false 删除失败
     */
    public boolean cancelAllAuthUser(Long roleId, Long[] userIds) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .from(SysUserRoleTable)
                .where(SysUserRoleTable.RoleId.eq(roleId))
                .and(SysUserRoleTable.UserId.in(Arrays.asList(userIds)));
        return sysUserRoleDao.remove(queryWrapper);
    }

    /**
     * 批量授权用户:新增用户和角色关联信息
     * insert into sys_user_role(user_id, role_id) values
     *
     * @param roleId  角色ID
     * @param userIds 需要新增的用户数据ID
     * @return 结果:true 保存成功，false 保存失败
     */
    public boolean authUser(Long roleId, Long[] userIds) {
        dataScopeService.checkRoleDataScope(roleId);
        boolean inserted = true;
        // 新增用户与角色管理
        List<SysUserRole> list = new ArrayList<>();
        Arrays.stream(userIds)
                .forEach(userId -> {
                    SysUserRole ur = new SysUserRole();
                    ur.setUserId(userId);
                    ur.setRoleId(roleId);
                    list.add(ur);
                });
        if (CollUtil.isNotEmpty(list)) {
            //批量插入
            inserted = sysUserRoleDao.saveBatch(list, 100);
        }
//        if (inserted){
//            cleanOnlineUserByRole(roleId);
//        }
        return inserted;
    }

    /**
     * 分配角色菜单权限:新增角色和菜单关联信息
     *
     * @param param 角色信息
     * @return 结果
     */
    @Transactional
    public boolean authMenu(SysRoleParam param) {
        SysRole entity = MapstructUtil.convert(param, SysRole.class);
        Assert.notNull(entity.getRoleId(), "修改对象不能为空");

        sysRoleDao.checkRoleAllowed(param);
        dataScopeService.checkRoleDataScope(param.getRoleId());

        // 修改角色信息
        sysRoleDao.updateById(entity);
        // 删除角色与菜单关联
        sysRoleMenuDao.removeRoleMenuByRoleId(param.getRoleId());
        // 新增角色菜单信息（数据权限）
        return sysRoleMenuDao.saveRoleMenu(param);
    }


    /**
     * 分配角色数据权限:新增角色和部门关联信息
     *
     * @param param 角色信息
     * @return 结果
     */
    @Transactional
    public boolean authDataScope(SysRoleParam param) {
        SysRole entity = MapstructUtil.convert(param, SysRole.class);
        Assert.notNull(entity, "修改对象不能为空");

        sysRoleDao.checkRoleAllowed(param);
        dataScopeService.checkRoleDataScope(param.getRoleId());

        // 修改角色信息
        sysRoleDao.updateById(entity);
        // 删除角色与部门关联
        sysRoleDeptDao.removeRoleDeptByRoleId(param.getRoleId());
        // 新增角色和部门信息（数据权限）
        return sysRoleDeptDao.saveRoleDept(param);
    }


    /**
     * 获取角色选择框列表
     **/
    public PageData<SysRoleVo> pageOptionSelect(PageQuery pageQuery) {
        QueryWrapper queryWrapper = sysRoleDao.buildQueryWrapperOptionSelect();
        return PageData.build(sysRoleDao.pageAs(pageQuery.build(), queryWrapper, SysRoleVo.class));
    }
}
